import re
from typing import Dict, List, Tuple

from pptx import Presentation


PLACEHOLDER_RE = re.compile(r"\{\{([^}]+)\}\}")


def open_template(path: str) -> Presentation:
    return Presentation(path)


def find_slide_map(prs: Presentation) -> Dict[str, int]:
    mapping: Dict[str, int] = {}
    for idx, slide in enumerate(prs.slides):
        for shape in slide.shapes:
            if not hasattr(shape, "has_text_frame"):
                continue
            if not shape.has_text_frame:
                continue
            text = shape.text_frame.text or ""
            m = re.search(r"\{\{slide:([^}]+)\}\}", text)
            if m:
                mapping[m.group(1).strip()] = idx
                break
    return mapping


def find_placeholders(slide) -> List[Tuple[str, object]]:
    results: List[Tuple[str, object]] = []
    for shape in slide.shapes:
        if hasattr(shape, "has_text_frame") and shape.has_text_frame:
            tf = shape.text_frame
            # check runs for more robust detection
            for para in tf.paragraphs:
                for run in para.runs:
                    for m in PLACEHOLDER_RE.finditer(run.text or ""):
                        results.append((m.group(1).strip(), shape))
                for m in PLACEHOLDER_RE.finditer(getattr(para, "text", "") or ""):
                    results.append((m.group(1).strip(), shape))
            # fallback to whole text
            for m in PLACEHOLDER_RE.finditer(tf.text or ""):
                results.append((m.group(1).strip(), shape))
    return results